class Beverage {
    boilWater() {
        console.log('把水煮沸');
    }

    brew() {
        throw new Error('子类必须重写 brew 方法');
    }

    pourInCup() {
        throw new Error('子类必须重写 pourInCup 方法');
    }

    addCondiments() {
        throw new Error('子类必须重写 addCondiments 方法');
    }

    // hook
    customerWantsCondiments() {
        return true;
    }

    /**
     * 这是模板方法！
     * 封装了子类算法框架。
     * 作为一个算法模板，指导子类以何种顺序去执行哪些方法
     */
    init() {
        this.boilWater();
        this.brew();
        this.pourInCup();
        if (this.customerWantsCondiments()) {
            this.addCondiments();
        }
    }
}

class Coffee extends Beverage {
    brew() {
        console.log('用沸水冲泡咖啡');
    }

    pourInCup() {
        console.log('把咖啡倒进杯子');
    }

    addCondiments() {
        console.log('加糖和牛奶');
    }
}

class Tea extends Beverage {
    brew() {
        console.log('用沸水冲泡茶叶');
    }

    pourInCup() {
        console.log('把茶叶倒进杯子');
    }

    addCondiments() {
        console.log('加柠檬');
    }
}

class CoffeeWithHook extends Beverage {
    brew() {
        console.log('用沸水冲泡咖啡');
    }

    pourInCup() {
        console.log('把咖啡倒进杯子');
    }

    addCondiments() {
        console.log('加糖和牛奶');
    }

    customerWantsCondiments() {
        return window.confirm('请问需要调料吗？');
    }
}

// test
let coffee = new Coffee();
coffee.init();

let tea = new Tea();
tea.init();
